from PySide6.QtWidgets import (
    QApplication,
    QSystemTrayIcon,
    QMenu,
    QWidget,
    QStyle,
    QProgressBar,
    QStyleOption,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QToolBar,
    QMessageBox,
)
from PySide6.QtGui import QAction, QIcon, QShowEvent, QPaintEvent, QPainter
from PySide6.QtCore import QProcess, QThread, Signal, QTimer, Qt, QSize
import os, sys, time
import image
import subprocess, psutil
import requests
import hashlib, math


class TrayIcon(QSystemTrayIcon):
    Trigger = Signal(int)

    def __init__(self, parent=None):
        super(TrayIcon, self).__init__(parent)
        menu = self.createMenu()
        self.setContextMenu(menu)
        self.setIcon(QIcon(":icon/logo.png"))
        self.setToolTip("My Tray App")

    def createMenu(self):
        self.menu = QMenu()
        self.quitAction = QAction(
            QApplication.style().standardIcon(QStyle.SP_BrowserStop),
            "退出",
            self,
            triggered=self.quit,
        )
        self.menu.addAction(self.quitAction)
        return self.menu

    def quit(self):
        # QApplication.quit()
        self.Trigger.emit(0)


class window(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.systemTrayIcon = TrayIcon(self)
        self.systemTrayIcon.show()
        self.systemTrayIcon.Trigger.connect(self.state)
        self.childPid = 0  # 初始化子进程pid

        self.resize(200, 40)
        self.setWindowTitle("Update")
        self.setWindowIcon(QIcon(":icon/logo.png"))
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowFlags(
            Qt.FramelessWindowHint | Qt.Tool  # | Qt.Window | Qt.WindowStaysOnTopHint
        )
        # 行0
        self.title = QLabel("检查更新...")
        self.title.setStyleSheet(
            """color: rgb(255, 255, 255);font-size: 12px;font-weight: bold;"""
        )
        self.toolbar = QToolBar()
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.addAction(
            QAction(
                QApplication.style().standardIcon(QStyle.SP_TitleBarCloseButton),
                "关闭",
                self,
            )
        )

        h0 = QHBoxLayout()
        h0.setContentsMargins(0, 0, 0, 0)
        h0.addWidget(self.title)
        h0.addStretch(1)
        h0.addWidget(self.toolbar)

        # 行1
        self.pros = QProgressBar(self)
        self.pros.setRange(0, 0)
        self.pros.setTextVisible(False)
        self.pros.setFixedHeight(4)
        # self.pros.setStyleSheet("height: 4px;border-radius:1px;")

        # 顶层
        v = QVBoxLayout(self)
        v.setContentsMargins(10, 10, 10, 20)
        v.addLayout(h0)
        v.addWidget(self.pros)

        # print("主进程:", os.getpid())
        # self.run = startChild(os.getpid(), self)
        # self.run.Trigger.connect(self.state)
        # self.run.start()
        self.setStyleSheet(
            """
        window {background-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:1, stop:0 rgba(14,70,200, 255), stop:1 rgba(255, 255, 255, 255)); border-radius: 5px;}        
        """
        )

        # 信号槽
        self.toolbar.actionTriggered.connect(self.MSG_SYSTEM)

        self.upload = downState(self)
        self.upload.Trigger.connect(self.doUpdate)
        self.upload.start()

    def MSG_SYSTEM(self, e):
        """系统工具栏消息"""
        if e.text() == "关闭":
            QApplication.quit()

    def doUpdate(self, e):
        """更新回调"""
        print(f"更新进度回调: {e}")
        if e == -3:
            QMessageBox.warning(self, "提示", "程序文件被占用")
        elif e == -2:
            QMessageBox.warning(self, "提示", "下载失败")
        elif e == -1:
            self.pros.setRange(0, 100)
        else:
            self.pros.setValue(e)

        if e < -1:
            self.start()

    def start(self):
        """开始主任务"""
        self.hide()
        print("主进程:", os.getpid())
        self.run = startChild(os.getpid(), self)
        self.run.Trigger.connect(self.state)
        self.run.start()

    def state(self, e):
        if not e:
            self.run.stop()
            self.terminate_process()
            self.run.wait()
            QApplication.quit()
        else:
            self.childPid = e

    def terminate_process(self):
        pid = self.childPid
        print("结束子线程:", pid)
        process_obj = psutil.Process(pid)
        # 枚举子进程
        sub_pid = [
            child_process.pid for child_process in process_obj.children(recursive=True)
        ]
        [os.kill(p, 15) for p in sub_pid]

    def paintEvent(self, event: QPaintEvent) -> None:
        opt = QStyleOption()
        opt.initFrom(self)
        p = QPainter(self)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
        return super().paintEvent(event)


class startChild(QThread):
    Trigger = Signal(int)

    def __init__(self, pid, parent=None):
        super(startChild, self).__init__(parent)
        self.pid = pid
        self.is_run = True

    def stop(self):
        self.is_run = False
        # self.process.terminate()
        # self.process.kill()
        # print("子线程被停止")

    def run(self):
        while self.is_run:
            process = subprocess.Popen(["XRrecord.exe", str(self.pid)])
            pid = process.pid
            self.Trigger.emit(pid)
            print("子进程:", pid)
            process.wait()
        print("子线程结束")


class downState(QThread):
    Trigger = Signal(int)
    host = "https://oss.3vppt.com/ppt_upload"

    def __init__(self, parent=None):
        super(downState, self).__init__(parent)
        self.is_run = True

    def stop(self):
        self.is_run = False

    def toHashMd5(self, md5):
        """计算md5值"""
        try:
            with open("XRrecord.exe", "rb") as f:
                return hashlib.md5(f.read()).hexdigest().upper() == md5
        except BaseException as err:
            return False

    def getIndex(self):
        """下载索引"""
        url = f"{self.host}/XRrecord.md"
        response = requests.get(url)  # stream=True
        if response.status_code == 200:  # 检查响应状态码
            print("文件下载完成！")
            return response.text.split(" ")
        else:
            print("下载失败，状态码：", response.status_code)
            return []

    def run(self):
        index = self.getIndex()
        if not self.toHashMd5(index[0]):
            print("文件已修改，开始下载")
            self.Trigger.emit(-1)
            url = f"{self.host}/XRrecord.exe"
            response = requests.get(url, stream=True)
            if response.status_code == 200:  # 检查响应状态码
                d = 0
                with open("XRrecord.tmp", "wb") as f:  # 打开本地文件进行写入操作
                    for chunk in response.iter_content(
                        chunk_size=512
                    ):  # 分块读取文件内容，每次读取1KB
                        if chunk:  # 检查是否有数据块可读
                            f.write(chunk)  # 将数据块写入本地文件
                            f.flush()  # 刷新缓冲区，确保数据写入磁盘
                            d += len(chunk)
                            print(d)
                            self.Trigger.emit(math.floor(d / int(index[1]) * 100))
                try:
                    os.remove("XRrecord.exe")
                except BaseException as err:
                    print("文件删除失败")
                try:
                    os.rename("XRrecord.tmp", "XRrecord.exe")
                except BaseException as err:
                    print("文件重命名失败")
                    self.Trigger.emit(-3)
                print("文件下载完成！")
            else:
                print("下载失败，状态码：", response.status_code)
                self.Trigger.emit(-2)
        else:
            self.Trigger.emit(-4)


if __name__ == "__main__":
    print("hello world")

    app = QApplication(sys.argv)
    if not QSystemTrayIcon.isSystemTrayAvailable():
        print("本系统检测不出系统托盘")
        sys.exit(1)
    tray_icon = window()
    tray_icon.show()
    sys.exit(app.exec())
